<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .wrap {
            padding: 10px;
        }

        .button-group {
            margin-bottom: 20px;
        }

        .button-group button {
            padding: 2.5px 5px;
        }

        .slide {
            width: 1100px;
            height: 100px;
            border: 1px solid #333;
            position: relative;
        }

        .slide .ball {
            width: 100px;
            height: 100px;
            background-color: pink;
            border-radius: 50px;
            position: absolute;
            left: 0px;
            top: 0;
        }
    </style>
</head>

<body>
    <div class="wrap">
        <div class="button-group">
            <button class="start">开始</button>
            <button class="pause">暂停</button>
            <button class="back">返回</button>
        </div>
        <div class="slide">
            <div class="ball"></div>
        </div>
    </div>
    <div class="wrap">
        <div class="button-group">
            <button class="start">开始</button>
            <button class="pause">暂停</button>
            <button class="back">返回</button>
        </div>
        <div class="slide">
            <div class="ball"></div>
        </div>
    </div>
    <div class="wrap">
        <div class="button-group">
            <button class="start">开始</button>
            <button class="pause">暂停</button>
            <button class="back">返回</button>
        </div>
        <div class="slide">
            <div class="ball"></div>
        </div>
    </div>

</body>
<script>

    // JS运动  => 本质: 没隔固定时间,控制元素移动指定距离

    // a.  没隔固定时间 => 计时器
    // b.  改变元素的位置 (margin position transform  -> position)


    var startList = document.getElementsByClassName("start");
    var pauseList = document.getElementsByClassName("pause");
    var backList = document.getElementsByClassName("back");
    var ballList = document.getElementsByClassName("ball");


    var slide = document.getElementsByClassName("slide")[0];
    var maxLeft = slide.clientWidth - ballList[0].clientWidth;



    document.onclick = function (e) {
        var e = e || window.event;
        var target = e.target;
        // console.log(target);
        if (target.className == "start") {
            // console.log("点击了开始", target);

            // 找到点击的start按钮 在startList集合中的下标
            var index = Array.from(startList).indexOf(target);
            var ball = ballList[index];

            animate(ball, { left: 1000 }, "slow", function () {
                console.log("到达终点:1000");
            });


        } else if (target.className == "pause") {
            // 找到点击的pause按钮 在pauseList集合中的下标
            var index = Array.from(pauseList).indexOf(target);
            var ball = ballList[index];

            clearInterval(ball.timer);
        } else if (target.className == "back") {
            // console.log("点击了开始", target);

            // 找到点击的back按钮 在backList集合中的下标
            var index = Array.from(backList).indexOf(target);
            var ball = ballList[index];

            animate(ball, { left: 0 }, "slow", function () {
                console.log("到达终点:0");
            });

        }


    }











    // ele    运动的元素
    // params  传入一个对象 (包含运动的属性及其终点值)
    // type    运动的方式  (slow  normal  fast)
    // callback  接收一个函数,每次运动完毕之后执行

    // 问题: 计时器的编号时全局变量  每次调用animate -> 先清除上一个,在启动下一个  -> 始终只有一个(下面的跑 上面的就停下来了)
    function animate(ele, params, type = "normal", callback) {
        // debugger;
        // callback 形参 -> 接收实际参数(本次有点特殊 -> 接收的是一个函数) 

        // 记录单属性运动的 cur end speed
        // var cur = ele.offsetLeft;  // 1. 记录小球的起始位置(left)  2. 每次运动后小球的位置
        // var cur = parseFloat(getStyle(ele, cssKey));  // 1. 记录小球的起始位置(left)  2. 每次运动后小球的位置
        // end = parseFloat(end); //去单位 ("1000px" => 1000)
        // var speed = 0;

        var cur = {};   // {left:当前值,top:当前值}
        var end = {};   // {left:终点,top:终点}  单位处理
        var speed = {}  // {left:速度,top:速度}  记录速度

        for (var cssKey in params) {  // csskey => 运动的css属性
            cur[cssKey] = parseFloat(getStyle(ele, cssKey));
            end[cssKey] = parseFloat(params[cssKey]);
            speed[cssKey] = 0;
        }
        // console.log("起始位置", cur);
        // console.log("终点", end);
        // console.log("速度", speed);

        // ele => 运动的元素(元素节点 -> 对象)  -> 元素节点的内置属性(className,id) 和 对象自定义属性
        // var data = {};
        // data.a = 1;
        // data.b = 2;

        // 将计时器的编号 作为元素的属性 存储到元素上(每个运动的元素都有一个timer属性 => 计时器的编号)
        // ele.timer = 1;

        clearInterval(ele.timer);
        ele.timer = setInterval(function () {

            // 多属性同时运动
            var isFinished = true;  // 假设都到达终点

            // {left:"1000px",top:500}
            for (var cssKey in params) {  // csskey => 运动的css属性  "left"  "top"

                if (type == "normal") {
                    // 匀速运动
                    if (end[cssKey] > cur[cssKey]) {
                        speed[cssKey] = 20
                    } else if (end[cssKey] < cur[cssKey]) {
                        speed[cssKey] = -20;
                    } else {
                        speed[cssKey] = 0;
                    }

                } else if (type == "fast") {
                    // 加速运动
                    if (end[cssKey] > cur[cssKey]) {  // 正向运动(0-1000   => speed正值)  
                        speed[cssKey] += 2;
                    } else if (end[cssKey] < cur[cssKey]) { // 反向运动(1000 - 0   => speed负值) 
                        speed[cssKey] -= 2;
                    } else {
                        speed[cssKey] = 0;
                    }

                } else if (type == "slow") {
                    // 缓冲运动
                    // (终点值 - 当前位置)  => 剩余的距离
                    // 剩余的距离 / 缓冲因子(n) => (每次剩余的n分之1)

                    // 缓冲因子 => 一般在8-12之间

                    if (end[cssKey] > cur[cssKey]) {
                        speed[cssKey] = (end[cssKey] - cur[cssKey]) / 10;  // speed >0 =>  可能会出现 0.00001
                        speed[cssKey] = Math.ceil(speed[cssKey]);  //  如果速度小于1  取  1
                    } else if (end[cssKey] < cur[cssKey]) {
                        speed[cssKey] = (end[cssKey] - cur[cssKey]) / 10;  // speed < 0 =>  可能会出现-0.00001
                        speed[cssKey] = Math.floor(speed[cssKey]);  //  如果速度大于-1  取  -1
                    } else {
                        speed[cssKey] = 0;
                    }

                }

                // console.log(speed);
                cur[cssKey] += speed[cssKey];  // 每次运动后小球的位置
                ele.style[cssKey] = cur[cssKey] + "px";

                if (Math.abs(cur[cssKey] - end[cssKey]) <= Math.abs(speed[cssKey])) {  // 到达终点后停下
                    ele.style[cssKey] = end[cssKey] + "px";  // 直接到达终点
                    delete params[cssKey];   //如果当前属性到达终点 => 移出该属性 (不会再遍历该属性)
                    // clearInterval(timer);   // 有一个到达终点就停下  
                } else {  // 有一个没到达终点   => 推翻假设
                    isFinished = false;
                }


            }
            // console.log(isFinished);
            if (isFinished) {   ///全都到达终点(本次运动结束)=> 清除计时器
                clearInterval(ele.timer);
                if (callback && typeof callback == "function") {  //如果callback有值 且 是函数
                    callback(); //执行该函数  -> 每次运动结束之后执行函数
                }
            }

        }, 10);
    }

    /* 获取非行内样式 */
    function getStyle(ele, cssKey) {
        if (window.getComputedStyle) {
            return window.getComputedStyle(ele)[cssKey];
        } else {
            return ele.currentStyle[cssKey];
        }
    }




</script>

</html>